static uword flowtable_getinfo(struct vlib_main_t *vm,
			struct vlib_node_runtime_t *node,struct vlib_frame_t *frame){

	u32 n_left_from, *from,*to_next;
	u32 next_index = node->cached_next_index;
	
	printf("flowtable_getinfo cached_next_index: %u\n", next_index);
	from = vlib_frame_vector_args(frame);//获取指向帧向量数据的指针，即第一个数据包的地址
    n_left_from = frame->n_vectors;	// 获取向量数量，即有多少个数据包

	while(n_left_from > 0){
		u32 n_left_to_next;
		// 获取下一个节点的帧和向量，然后vlib_put_next_frame将当前节点处理的数据包添加到这个帧中，
		// 以便后续的节点可以处理这些数据包，最开始这里是获取的第一帧，一帧里面有多个vlib_buffer
		// 可以看做为二维数组
		vlib_get_next_frame(vm,node,next_index,to_next,n_left_to_next);

		//n_left_to_next 是当前帧中剩余的空闲槽位数量,
        //当值为0后，需要vlib_put_next_frame获取一个,新的帧来继续传递数据包
            while(n_left_from > 0 && n_left_to_next > 0){

			vlib_buffer_t *b0;
			u32 bi0,next0 = 0;

			bi0 = to_next[0] = from[0];
			from += 1;
			to_next += 1;
			n_left_to_next -= 1;
			n_left_from -= 1;

			//它将 DPDK 的 rte_mbuf 转换为 VPP 的 vlib_buffer_t,vlib_buffer_t里面有多个rte_mbuf(数据包)
			b0 = vlib_get_buffer(vm,bi0);
			//取出当前需要处理的数据包
			ip4_header_t *ip0 = vlib_buffer_get_current(b0);
			ip4_address_t ip_src = ip0->src_address;
			ip4_address_t ip_dst = ip0->dst_address;
			//获取处理的数据包所到达的接口的软件索引，并将其存储在变量 sw_if_index0 中
			u32 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
			//对每个数据包打印 其源ip及目的ip
			struct in_addr addr;
			addr.s_addr = ip_src.as_u32;
			printf("sw_if_index0: %d, ip_src: %s ", sw_if_index0, inet_ntoa(addr));
			addr.s_addr = ip_dst.as_u32;
			printf(" ip_dst: %s \n", inet_ntoa(addr));


			// 将当前处理的缓冲区 bi0 传递到下一个节点，同时更新 to_next 数组、n_left_to_next 计数
			// 和下一个节点的下一个节点索引 next0。这样，数据包将会在当前节点处理后传递到下一个节点进行进一步处理
			vlib_validate_buffer_enqueue_x1(vm,node,next_index,
				to_next,n_left_to_next,bi0,next0);
		}
		// vlib_get_next_frame获取下一个节点的帧和向量，然后vlib_put_next_frame将当前节点处理的数据
		// 包添加到这个帧中，以便后续的节点可以处理这些数据包
		vlib_put_next_frame(vm,node,next_index,n_left_to_next);
	}
	return frame->n_vectors; 
}